Resizegrad ================= 计算 Resize 操作的梯度。该算子包含两种实现:最近邻插值梯度(ResizeNearestNeighborGrad)和双线性插值梯度(ResizeBiLinearGrad)。用于将上游梯度从输出尺寸反向传播到输入尺寸。 最近邻插值梯度(ResizeNearestNeighborGrad) 对于最近邻插值,输入梯度通过最近邻映射反向传播到输出梯度。 .. math:: out_y = \begin{cases} \mathrm{round}(in_y \cdot height\_scale), & \text{if } align\_corners \\ \lfloor in_y \cdot height\_scale \rfloor, & \text{otherwise} \end{cases} .. math:: out_x = \begin{cases} \mathrm{round}(in_x \cdot width\_scale), & \text{if } align\_corners \\ \lfloor in_x \cdot width\_scale \rfloor, & \text{otherwise} \end{cases} .. math:: out\_addr[out\_offset] \mathrel{+}= in\_addr[in\_offset] 其中 `in_addr` 是上游梯度(输出尺寸),`out_addr` 是输入梯度(输入尺寸)。注意使用累加操作(+=),因为多个输入位置可能映射到同一个输出位置。 双线性插值梯度(ResizeBiLinearGrad) 对于双线性插值,输入梯度通过双线性插值的反向传播分配到4个相邻的输出位置。 .. math:: in_y = h \cdot height\_scale .. math:: top_y = \max(\lfloor in_y \rfloor, 0) .. math:: bottom_y = \min(\lceil in_y \rceil, out\_height - 1) .. math:: y_{\mathrm{lerp}} = in_y - \lfloor in_y \rfloor .. math:: inverse\_y\_lerp = 1.0 - y_{\mathrm{lerp}} 对于 x 维度有类似的公式: .. math:: in_x = w \cdot width\_scale .. math:: left_x = \max(\lfloor in_x \rfloor, 0) .. math:: right_x = \min(\lceil in_x \rceil, out\_width - 1) .. math:: x_{\mathrm{lerp}} = in_x - \lfloor in_x \rfloor .. math:: inverse\_x\_lerp = 1.0 - x_{\mathrm{lerp}} 输入梯度按权重分配到4个相邻位置: .. math:: out\_addr[top_y, left_x] \mathrel{+}= in\_addr[h, w] \cdot (inverse\_y\_lerp \cdot inverse\_x\_lerp) .. math:: out\_addr[top_y, right_x] \mathrel{+}= in\_addr[h, w] \cdot (inverse\_y\_lerp \cdot x_{\mathrm{lerp}}) .. math:: out\_addr[bottom_y, left_x] \mathrel{+}= in\_addr[h, w] \cdot (y_{\mathrm{lerp}} \cdot inverse\_x\_lerp) .. math:: out\_addr[bottom_y, right_x] \mathrel{+}= in\_addr[h, w] \cdot (y_{\mathrm{lerp}} \cdot x_{\mathrm{lerp}}) 输入: - **in_addr** - 指向上游梯度数据的指针(输出尺寸的梯度)。 - **out_addr** - 指向输出梯度数据的指针(输入尺寸的梯度),需要初始化为0。 - **batch_size** - 批次大小。 - **channel** - 通道数。 - **format** - 数据格式,0 表示 NHWC,1 表示 NCHW。 - **align_corners** - 是否对齐角点标志,0 表示不对齐,1 表示对齐。 - **in_height** - 输入高度。 - **in_width** - 输入宽度。 - **out_height** - 输出高度。 - **out_width** - 输出宽度。 - **height_scale** - 高度缩放因子,通常为 (out_height - 1) / (in_height - 1) 或 out_height / in_height。 - **width_scale** - 宽度缩放因子,通常为 (out_width - 1) / (in_width - 1) 或 out_width / in_width。 输出: - **out_addr** - 计算后的输入梯度(输入尺寸的梯度)。 支持平台: ``FT78NE`` ``MT7004`` .. note:: - FT78NE 支持 fp32 - MT7004 支持 fp16, fp32 **共享存储版本:** .. c:function:: void fp_resizenearestneighborgrad_s(float* in_addr, float* out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale, int core_mask) .. c:function:: void hp_resizenearestneighborgrad_s(half* in_addr, half* out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale, int core_mask) .. c:function:: void fp_resizebilineargrad_s(float* in_addr, float* out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale, int core_mask) .. c:function:: void hp_resizebilineargrad_s(half* in_addr, half* out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale, int core_mask) **C调用示例(最近邻插值梯度):** .. code-block:: c :linenos: :emphasize-lines: 22-24 #include #include int main(int argc, char* argv[]) { float *in_addr = (float *)0x10010000; float *out_addr = (float *)0x10020000; int batch_size = 4; int channel = 3; int format = 1; int align_corners = 1; int in_height = 4, in_width = 4; int out_height = 6, out_width = 6; int core_mask = 0xff; float height_scale = (float)(out_height - 1) / (in_height - 1); float width_scale = (float)(out_width - 1) / (in_width - 1); int output_size = in_height * in_width * channel * batch_size; memset(out_addr, 0, output_size * sizeof(float)); fp_resizenearestneighborgrad_s(in_addr, out_addr, batch_size, channel, format, align_corners, in_height, in_width, out_height, out_width, height_scale, width_scale, core_mask); return 0; } **私有存储版本:** .. c:function:: void fp_resizenearestneighborgrad_p(float* in_addr, float* out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale) .. c:function:: void hp_resizenearestneighborgrad_p(half* in_addr, half* out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale) .. c:function:: void fp_resizebilineargrad_p(float* in_addr, float* out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale) .. c:function:: void hp_resizebilineargrad_p(half* in_addr, half* out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale) **C调用示例(双线性插值梯度):** .. code-block:: c :linenos: :emphasize-lines: 21-23 #include #include int main(int argc, char* argv[]) { float *in_addr = (float *)0x10010000; float *out_addr = (float *)0x10020000; int batch_size = 4; int channel = 3; int format = 0; int align_corners = 0; int in_height = 4, in_width = 4; int out_height = 6, out_width = 6; float height_scale = (float)out_height / in_height; float width_scale = (float)out_width / in_width; int output_size = in_height * in_width * channel * batch_size; memset(out_addr, 0, output_size * sizeof(float)); fp_resizebilineargrad_p(in_addr, out_addr, batch_size, channel, format, align_corners, in_height, in_width, out_height, out_width, height_scale, width_scale); return 0; }